#include "SQLUnionQueryTableSource.h"
#include "../../../utils/ifeq.h"
#include "../../../utils/hashCodeList.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/common_ptr.h"
#include "SQLSelectItem.h"

SQLUnionQueryTableSource::SQLUnionQueryTableSource()
{
  columns = std::make_shared<std::list<SQLName_ptr>>();
}

SQLUnionQueryTableSource::SQLUnionQueryTableSource(string_ptr alias)
    : SQLTableSourceImpl(alias)
{
  columns = std::make_shared<std::list<SQLName_ptr>>();
}

SQLUnionQueryTableSource::SQLUnionQueryTableSource(SQLUnionQuery_ptr xunion, string_ptr alias)
    : SQLTableSourceImpl(alias)
{
  this->setUnion(xunion);
  columns = std::make_shared<std::list<SQLName_ptr>>();
}

SQLUnionQueryTableSource::SQLUnionQueryTableSource(SQLUnionQuery_ptr xunion)
{
  this->setUnion(xunion);
  columns = std::make_shared<std::list<SQLName_ptr>>();
}

void SQLUnionQueryTableSource::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLUnionQueryTableSource)))
  {
    if (xunion != NULL)
    {
      xunion->accept(visitor);
    }
  }
  visitor->endVisit(SharedObject(SQLUnionQueryTableSource));
}

void SQLUnionQueryTableSource::output(std::stringstream * buf)
{
  // try
  // {
  (*buf)<<"(";
  this->xunion->output(buf);
  (*buf)<<")";
  // }
  // catch (IOException ex)
  // {
  //   throw new FastsqlException("output error", ex);
  // }
}

SQLUnionQuery_ptr SQLUnionQueryTableSource::getUnion()
{
  return xunion;
}

void SQLUnionQueryTableSource::setUnion(SQLUnionQuery_ptr xunion)
{
  if (xunion != NULL)
  {
    xunion->setParent(SharedObject(SQLUnionQueryTableSource));
  }
  this->xunion = xunion;
}

SQLObject_ptr SQLUnionQueryTableSource::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLUnionQueryTableSource>(new SQLUnionQueryTableSource(std::dynamic_pointer_cast<SQLUnionQuery>(this->xunion->clone()), alias));
  std::shared_ptr<SQLUnionQueryTableSource> x = std::dynamic_pointer_cast<SQLUnionQueryTableSource>(clone_tmp);
  // SQLUnionQueryTableSource *x = new SQLUnionQueryTableSource(this->xunion->clone(), alias);

  if (this->flashback != NULL)
  {
    x->setFlashback(std::dynamic_pointer_cast<SQLExpr>(this->flashback->clone()));
  }

  if (!this->hints->empty())
  {
    for (SQLHint_ptr e : *this->hints)
    {
      SQLHint_ptr e2 = std::dynamic_pointer_cast<SQLHint>(e->clone());
      e2->setParent(std::dynamic_pointer_cast<SQLHint>(x));
      x->getHints()->push_back(e2);
    }
  }

  return x;
}

SQLName_list_ptr SQLUnionQueryTableSource::getColumns()
{
  return columns;
}

bool SQLUnionQueryTableSource::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == NULL || getClass() != o->getClass())
  {
    return false;
  }
  if (!SQLTableSourceImpl::equals(o))
  {
    return false;
  }

  std::shared_ptr<SQLUnionQueryTableSource> that = std::dynamic_pointer_cast<SQLUnionQueryTableSource>(o);

  if (xunion != NULL ? !xunion->equals(std::dynamic_pointer_cast<Object>(that->xunion)) : that->xunion != NULL)
  {
    return false;
  }
  return !columns->empty() ? IFEQ::ifeq(columns, that->columns) : that->columns->empty();
}

int SQLUnionQueryTableSource::hashCode()
{
  int result = SQLTableSourceImpl::hashCode();
  result = 31 * result + (xunion != NULL ? xunion->hashCode() : 0);
  result = 31 * result + (!columns->empty() ? utils::hashCodeList<SQLName>(columns) : 0);
  return result;
}

SQLTableSource_ptr SQLUnionQueryTableSource::findTableSourceWithColumn(long columnNameHash, string_ptr columnName, int option)
{
  if (xunion == NULL)
  {
    return NULL;
  }

  SQLSelectQueryBlock_ptr firstQueryBlock = xunion->getFirstQueryBlock();
  if (firstQueryBlock != NULL)
  {
    SQLSelectItem_ptr selectItem = firstQueryBlock->findSelectItem(columnNameHash);
    if (selectItem != NULL)
    {
      return SharedObject(SQLUnionQueryTableSource);
    }
  }
  return NULL;
}
